#!/usr/bin/env ruby
#
=begin
    Creates and sets Outlook signatures
    Copyright (C) 2014  Oliver Hills / R-Group International

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/
=end

# Script is designed to pull data from AD and then spit
# out a html signature file for use in Outlook
require 'win32ole'
require 'optparse'
require 'ostruct'
require 'fileutils'
#require 'win32/registry'

def fixoutfoldernames(filename)
  signamenoext = filename.chomp(File.extname(filename))
  copyfolder = signamenoext + '_files'
  return copyfolder
end

# Sets possible cmd line options
class Optparse
  def self.parse(args)
    # Sets defaults
    options = OpenStruct.new
    options.silent = false
    options.testrun = false
    options.inputfile = 'input.htm'
    options.outputfile = options.inputfile
    options.folder = nil
    options.default = 'none'

    opt_parser = OptionParser.new do |opts|

      opts.banner = 'Usage: example.rb [options]'

      opts.on('-s', '--silent', 'Run silently') do
        options.silent = true
      end

      opts.on('-t', '--test', 'output to local folder only') do
        options.testrun = true
      end

      opts.on('-i', '--input', '-i [file] specify input HTML file defaults to input.htm in script dir') do |i|
        options.inputfile = i
        options.outputfile = options.inputfile
      end

      opts.on('-f', '--folder', '-f [folder] Folder to copy defaults to %outputfilename%_files in script dir') do |f|
        options.folder = f
      end

      opts.on('-o', '--outfilename', '-o [filename] Output filename default = input filename') do |o|
        options.outputfile = o
      end

      opts.on('-d', '--default', '-d [new/reply/both/none] Set sig as default for, def = none') do |d|
        d = d.downcase
        if d == 'new'
          options.default = 'new'
        elsif d == 'reply'
          options.default = 'reply'
        elsif d == 'both'
          options.default = 'both'
        elsif d == 'none'
          options.default = 'none'
        else
          puts 'Invalid option for -d try new/reply/both/none'
          exit
        end
      end

    end

    opt_parser.parse!(args)
    options
  end # End parse
end # End Optparse class

options = Optparse.parse(ARGV)

# Set options folder to default if left as nil
if options.folder.nil? then options.folder = fixoutfoldernames(options.outputfile) end

# Tell user if out folder is going to cause problems
if options.folder.include? '_files'
else
  puts "#{options.folder} does not contain _files this may cause some problems with outlook allowing images"
end

# Test out folder exists and warn users if not
if File.directory?(options.folder) == false
  puts "#{options.folder} cannot be found if you are expecting to have images this may cause problems"
end

# Swap \'s with /'s so copy paths work
def fixpath(str)
  str.gsub!('\\', '/')
end

fixpath(options.folder)

# Search input file for data to work on
possiblevalues = ['++firstname++',
                  '++initials++',
                  '++lastname++',
                  '++fullname++',
                  '++description++',
                  '++wwwhomepage++',
                  '++street++',
                  '++city++', # LDAP lookup l
                  '++state++', # LDAP lookup st
                  '++postalcode++',
                  '++countryabbreviation++', # LDAP lookup c
                  '++countryfull++', # LDAP lookup co
                  '++pager++',
                  '++faxnumber++', # LDAP lookup facsimileTelephoneNumber
                  '++ipphone++',
                  '++homephone++',
                  '++department++',
                  '++company++',
                  '++division++',
                  '++title++',
                  '++mail++',
                  '++telephonenumber++',
                  '++mobile++']

existingvalues = []
File.foreach(options.inputfile) do |line|
  possiblevalues.each do |value|
    existingvalues << value if line.downcase.include? value
  end
end

# Convert  to ldap names
ldapvalues = []
existingvalues.each do |value|
  value = value.gsub('++', '')
  ldapvalues << value
end

# If this is a test run then output to same folder else output to
# Outlook folder and copy images folder as well
if options.testrun == true
  of = options.outputfile
else
  outfolder = ENV['APPDATA'] + '\\Microsoft\\Signatures\\'
  of =  outfolder + options.outputfile
  FileUtils.cp_r(Dir[options.folder], outfolder)
end

# checks if vars are empty class should be expanded
class GetData
  def self.checkempty(data)
    data.nil?
  end
end

# Gets LDAP info for user and sets up ldap lookup
network = WIN32OLE.new('ADSystemInfo')
userldap = network.UserName

ldap = WIN32OLE.connect("LDAP://#{userldap}")

data = {}
ldapvalues.each do |v|
  if v == 'fullname'
    data.merge!(v => ldap.FullName)
  elsif v == 'title'
    data.merge!(v => ldap.Title)
  elsif v == 'mail'
    data.merge!(v => ldap.mail)
  elsif v == 'telephonenumber'
    data.merge!(v => ldap.TelephoneNumber)
  elsif v == 'mobile'
    data.merge!(v => ldap.mobile)
  elsif v == 'initials'
    data.merge!(v => ldap.initials)
  elsif v == 'lastname'
    data.merge!(v => ldap.lastname)
  elsif v == 'description'
    data.merge!(v => ldap.description)
  elsif v == 'wwwhomepage'
    data.merge!(v => ldap.wwwhomepage)
  elsif v == 'street'
    data.merge!(v => ldap.street)
  elsif v == 'city'
    data.merge!(v => ldap.l)
  elsif v == 'state'
    data.merge!(v => ldap.st)
  elsif v == 'postalcode'
    data.merge!(v => ldap.postalcode)
  elsif v == 'countryabbreviation'
    data.merge!(v => ldap.c)
  elsif v == 'countryfull'
    data.merge!(v => ldap.co)
  elsif v == 'pager'
    data.merge!(v => ldap.pager)
  elsif v == 'faxnumber'
    data.merge!(v => ldap.facsimileTelephoneNumber)
  elsif v == 'ipphone'
    data.merge!(v => ldap.ipphone)
  elsif v == 'homephone'
    data.merge!(v => ldap.homephone)
  elsif v == 'department'
    data.merge!(v => ldap.department)
  elsif v == 'company'
    data.merge!(v => ldap.company)
  elsif v == 'division'
    data.merge!(v => ldap.division)
  elsif v == 'title'
    data.merge!(v => ldap.title)
  elsif v == 'firstname'
    data.merge!(v => ldap.name)
  end
end

# Creats empty hash table for data to be merged into
datagot = {}
# If not silent checks first hash table for nil values and if found asks user to
# input Once it has a value it merges data with the second hash table
def notsilent(data, datagot)
  data.each do |key, value|
    if GetData.checkempty(value)
      print "No value for #{key} could be found please enter one here: "
      newval = gets.chomp
      datagot.merge!(key => newval)
    else
      datagot.merge!(key => value)
    end
  end
end

# Does pretty much the same as not silent but puts whitespace if value is nil
# so no nil values exist in hash table
def silent(data, datagot)
  data.each do |key, value|
    if GetData.checkempty(value)
      datagot.merge!(key => ' ')
    else
      datagot.merge!(key => value)
    end
  end
end

if options.silent == false
  notsilent(data, datagot)
else
  silent(data, datagot)
end

# Check if output file exists and delete it
if File.file?(of)
  File.delete(of)
  puts "#{of} exists deleting it now"
end

# append to file
def append(data, outputfile)
  File.open(outputfile, 'a') { |f| f.write(data) }
end

# Find and replace text then append to file
def fra(line, find, replace, outputfile)
  replace = ' ' if replace.nil?
  line = line.gsub!(find, replace)
  append(line, outputfile)
end

# Check file line by line and if anything in the line matches questions
# run find replace else just append the line
File.foreach(options.inputfile) do |l|
  if  existingvalues.any? { |v| l[v] }
    fra(l, '++fullname++', datagot['fullname'], of)
    fra(l, '++title++', datagot['title'], of)
    fra(l, '++mail++', datagot['mail'], of)
    fra(l, '++mobile++', datagot['mobile'], of)
    fra(l, '++telephonenumber++', datagot['telephonenumber'], of)
    fra(l, '++firstname++', datagot['firstname'], of)
    fra(l, '++initials++', datagot['initials'], of)
    fra(l, '++lastname++', datagot['lastname'], of)
    fra(l, '++description++', datagot['description'], of)
    fra(l, '++wwwhomepage++', datagot['wwwhomepage'], of)
    fra(l, '++street++', datagot['street'], of)
    fra(l, '++city++', datagot['city'], of)
    fra(l, '++state++', datagot['state'], of)
    fra(l, '++postalcode++', datagot['postalcode'], of)
    fra(l, '++countryabbreviation++', datagot['countryabbreviation'], of)
    fra(l, '++countryfull++', datagot['countryfull'], of)
    fra(l, '++pager++', datagot['pager'], of)
    fra(l, '++faxnumber++', datagot['faxnumber'], of)
    fra(l, '++ipphone++', datagot['ipphone'], of)
    fra(l, '++department++', datagot['department'], of)
    fra(l, '++company++', datagot['company'], of)
    fra(l, '++division++', datagot['division'], of)
  else
    append(l, of)
  end
end

=begin
# Set new signature as default

def writereg(folder, key, value)
  # Set access to allow write
  access = Win32::Registry::KEY_ALL_ACCESS
  begin
    # Connect to correct folder
    Win32::Registry::HKEY_CURRENT_USER.open(folder, access) do |reg|
      # Write the actual key
      reg.write(key, Win32::Registry::REG_EXPAND_SZ, value)
    end
  rescue
    puts "#{folder} does not exist probably just a different Office version"
  end
end

officevers = ['12.0', '14.0', '15.0']
outfile = options.outputfile
outfile = outfile.chomp(File.extname(outfile))

 officevers.each do |version|
  folder = 'Software\Microsoft\Office\\' + version + '\Outlook\Setup'
  writereg(folder, 'First-Rub', nil)
  
  folder = 'Software\Microsoft\Office\\' + version + '\Common\MailSettings'
  if options.default == 'new'
    writereg(folder, 'NewSignature', outfile)
  elsif options.default == 'reply'
    writereg(folder, 'ReplySignature', outfile)
  elsif options.default == 'both'
    writereg(folder, 'ReplySignature', outfile)
    writereg(folder, 'NewSignature', outfile)
  end
end
=end

# Sets sigs to default using MSWord
class WordSigs
  
  def initialize(file)
    @outfile = file.chomp(File.extname(file))
    @outfile = @outfile.chomp
    @word = WIN32OLE.new('Word.Application')
    @emailoptions = @word.emailoptions
    @signatureobject = @emailoptions.emailsignature
  end

  def both
    @signatureobject.NewMessageSignature = @outfile
    @signatureobject.ReplyMessageSignature = @outfile
  end

  def new
    @signatureobject.NewMessageSignature = @outfile
  end

  def reply
    @signatureobject.ReplyMessageSignature = @outfile
  end
end

if options.default == 'none'
  else
    ws = WordSigs.new(options.outputfile)
    if options.default = 'both'
      ws.both
    elsif options.default = 'new'
      ws.new
    elsif options.default = 'reply'
      ws.reply
    end
end
